package com.notary.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.code.kaptcha.Producer;
import com.notary.config.NotaryProperties;
import com.notary.constants.Constant;
import com.notary.entity.Notary;
import com.notary.entity.SysUser;
import com.notary.entity.po.LoginDTO;
import com.notary.entity.po.ModifyPwdDTO;
import com.notary.entity.vo.JsonResult;
import com.notary.service.NotaryService;
import com.notary.service.SysUserService;
import com.notary.sms.SmsUtil;
import com.notary.util.DesUtil;
import com.notary.util.JuHeUtil;
import com.notary.util.JwtUtil;
import com.sun.crypto.provider.HmacMD5;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import net.bytebuddy.asm.Advice;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 登录相关
 * </p>
 *
 * @author xujun
 * @since 2020-07-28
 */


@Api(tags = "登录控制器")
@RequestMapping("/user")
@RestController
@Validated
public class SysLoginController {

    @Autowired
    private Producer producer;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    SysUserService userService;

    @Autowired
    NotaryService notaryService;

    @Autowired
    JuHeUtil juHeUtil;

    @Autowired
    NotaryProperties notaryProperties;

    @ApiOperation(value = "图形验证码")
    @ApiImplicitParam(name = "Authorization", value = "token", required = false, dataType = "String", paramType = "header")
    @GetMapping("/captcha.jpg")
    public void captcha(HttpServletResponse response) throws IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        //生成文字验证码
        String text = producer.createText();
        //生成图片验证码
        BufferedImage image = producer.createImage(text);
        //保存到redis
        redisTemplate.opsForValue().set(Constant.CAPTCHA_KEY, text, 120, TimeUnit.SECONDS);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
    }

    /**
     * 短信登录
     */
    @ApiOperation(value = "密码登录")
    @ApiImplicitParam(name = "Authorization", value = "token", required = false, dataType = "String", paramType = "header")
    @PostMapping("/login")
    public JSONObject login(@RequestBody LoginDTO loginDTO) throws Exception {
        String username = loginDTO.getUsername();
        String password = SecureUtil.md5(loginDTO.getPassword());
        SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("username", username).eq("password", password));
        if (user == null) return new JSONObject() {{
            put("code", 201);
            put("msg", "登陆信息错误");
        }};
        Notary notary = notaryService.getOne(new QueryWrapper<Notary>().eq("user_id", user.getUserId()));
        user.setNotaryName(notary.getName());
        user.setOfficeCode(notaryProperties.getCode());
        String token = JwtUtil.createJWT(user, JwtUtil.JWT_TTL);
        String tokenStr = JwtUtil.TOKEN_PREFIX + token;
        // response.setHeader(JwtUtil.TOKEN_HEADER, tokenStr);
        //登录成功把token放进redis
        JSONObject data = new JSONObject();
        data.put("code", "200");
        data.put("msg", "");
        if (!Objects.equals(user.getFaceFlag(), 1)) {
            data.put("flag", "0");
            data.put("data", tokenStr);
        } else {
            data.put("userId", user.getUserId());
            data.put("orderNo", generateOrderNo());
            data.put("name", notary.getName());
            data.put("idNo", notary.getIdCard());
            data.put("flag", "1");
        }
        redisTemplate.opsForValue().set(username, tokenStr, 30, TimeUnit.DAYS);
        if (notaryProperties.getIsDes() == 1) {
            JSONObject result = new JSONObject();
            result.put("code", "200");
            result.put("msg", "");
            String encodeData = DesUtil.encode(notaryProperties.getDeskey(), notaryProperties.getDesIv(), data.toString());
            result.put("data", encodeData);
            return result;
        } else {
            return data;
        }

    }

    private String generateOrderNo() {
        StringBuilder sb = new StringBuilder();
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String key = "REDIS_KEY_PREFIX_FACE_ORDERNO" + date;
        Long increment = redisTemplate.opsForValue().increment(key, 1);
        if (increment == 1) {
            redisTemplate.expire(key, 30, TimeUnit.DAYS);// 设置失效时间 每天从1开始
        }
        sb.append(date);
        String incrementStr = increment.toString();
        if (incrementStr.length() <= 6) {
            sb.append(String.format("%06d", increment));
        } else {
            sb.append(incrementStr);
        }
        return "Face" + sb.toString();
    }

    /**
     * 短信登录
     */
    @ApiOperation(value = "退出登录")
    @ApiImplicitParam(name = "Authorization", value = "token", required = false, dataType = "String", paramType = "header")
    @GetMapping("/logout")
    public JsonResult logout(@RequestParam String username) {
        redisTemplate.opsForValue().set(username, null);
        return JsonResult.success();
    }

    /**
     * 修改密码
     */
    @ApiOperation(value = "发送短信验证码")
    @GetMapping("/sendSmsCode")
    public JsonResult sendSmsCode(@RequestParam @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格有误") String phone) {
        JsonResult result = null;
        Long count = redisTemplate.opsForValue().increment("LIMIT_ONE_DAY_" + phone, 0);
        if (count > 10) {
            return JsonResult.fail("今日发送短信次数已到达上限");
        }
        String smsCode = RandomUtil.randomNumbers(6);
        Map<String, String> param = new HashMap<String, String>();
        param.put("code", smsCode);
        try {
            result = juHeUtil.sendSms(phone, "216965", param);
            redisTemplate.opsForValue().set(phone, smsCode, 90, TimeUnit.SECONDS);
            redisTemplate.opsForValue().increment("LIMIT_ONE_DAY_" + phone, 1);
            redisTemplate.expire("LIMIT_ONE_DAY_" + phone, 1, TimeUnit.DAYS);
        } catch (Exception e) {
            System.out.println("发送短信失败:" + e.getMessage());
        }
        return result;
    }

    /**
     * 修改密码
     */
    @ApiOperation(value = "修改密码")
    @PostMapping("/modifyPwd")
    public JsonResult modifyPwd(@RequestBody @Valid ModifyPwdDTO modifyPwdDTO) {
        String phone = modifyPwdDTO.getPhone();
        String smsCode = modifyPwdDTO.getSmsCode();
        String password = modifyPwdDTO.getPassword();
        if (!Objects.equals(redisTemplate.opsForValue().get(phone), smsCode)) {
            return JsonResult.fail("验证码错误");
        }
        SysUser user = userService.getOne(new QueryWrapper<SysUser>().eq("username", password).or().eq("mobile", phone));
        if (user == null) {
            return JsonResult.fail("该手机号未绑定");
        }
        user.setPassword(SecureUtil.md5(password));
        userService.update(user, new UpdateWrapper<SysUser>().eq("mobile", phone));
        return JsonResult.success();
    }


}
